package config

import (
	"log"
	"sort"
	"sync"

	"tuiwen-go/internal/db"
)

type Setting struct {
	Id    int    `json:"id"`
	Key   string `json:"key"`
	Value string `json:"value"`
	Name  string `json:"name"`
}

var (
	settings     map[string]Setting
	settingsLock sync.RWMutex
)

// InitSettings loads all settings from the database into memory.
func InitSettings() error {
	log.Println("正在从数据库加载设置...")
	rows, err := db.Query("SELECT id, `key`, `name`, value FROM setting")
	if err != nil {
		return err
	}
	defer rows.Close()

	newSettings := make(map[string]Setting)
	for rows.Next() {
		var id int
		var key, value, name string
		if err := rows.Scan(&id, &key, &name, &value); err != nil {
			log.Printf("扫描设置时出错: %v", err)
			continue
		}
		newSettings[key] = Setting{Id: id, Key: key, Value: value, Name: name}
	}

	settingsLock.Lock()
	settings = newSettings
	settingsLock.Unlock()
	log.Println("设置加载完成。")
	return nil
}

// GetSetting retrieves a setting value from the cache.
func GetSetting(key string) (string, bool) {
	settingsLock.RLock()
	defer settingsLock.RUnlock()
	value, ok := settings[key]
	return value.Value, ok
}

// GetAllSettings retrieves all settings from the cache.
func GetAllSettings() []Setting {
	InitSettings()
	settingsLock.RLock()
	defer settingsLock.RUnlock()
	// Return a copy to prevent external modification
	var allSettings []Setting
	for _, v := range settings {
		allSettings = append(allSettings, v)
	}

	// Sort the settings by Key to ensure consistent order
	sort.Slice(allSettings, func(i, j int) bool {
		return allSettings[i].Id < allSettings[j].Id
	})

	// Mask gpt_accesskey value
	for i := range allSettings {
		if allSettings[i].Key == "gpt_accesskey" {
			allSettings[i].Value = "***"
			break
		}
	}

	return allSettings
}

// SetSetting updates a setting value in the cache and in the database.
func UpdateSetting(key, value string) error {
	settingsLock.Lock()
	// Update in-memory cache
	if s, ok := settings[key]; ok {
		s.Value = value
		settings[key] = s
	} else {
		// If it's a new setting, we don't have an ID yet, so we'll add it after DB insert
		settings[key] = Setting{Key: key, Value: value}
	}
	settingsLock.Unlock()

	// Update in database
	result, err := db.Exec("update setting set `value` = ? where `key` = ?", value, key)
	if err != nil {
		return err
	}

	// If it was an insert, get the last insert ID and update the in-memory setting with it
	if rowsAffected, _ := result.RowsAffected(); rowsAffected > 0 {
		if id, err := result.LastInsertId(); err == nil {
			settingsLock.Lock()
			if s, ok := settings[key]; ok {
				s.Id = int(id)
				settings[key] = s
			}
			settingsLock.Unlock()
		}
	}

	return nil
}
